----------------------------------------------------------------------------------

--REFERENCE : http://vhdlguru.blogspot.com/2011/01/block-and-distributed-rams-on-xilinx.html
----------------------------------------------------------------------------------

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_SIGNED.ALL;

PACKAGE MemoryPackage IS
	component Memory
		GENERIC ( memSize 	 : integer;--The size of each memory elements, in bits
					addressBits : integer);--The number of elements
		port(	Clk : in std_logic;
			  address : in std_logic_vector((addressBits - 1) downto 0);
			  we : in std_logic;
			  data_i : in std_logic_vector((memSize-1) downto 0);
			  data_o : out std_logic_vector((memSize-1) downto 0)
			);
	end component;
END MemoryPackage;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_SIGNED.ALL;

entity Memory is
	GENERIC ( memSize 	 : integer;--The size of each memory elements, in bits
				 addressBits : integer);--The number of bits used to represent the address
	port (Clk : in std_logic;
			  address : in std_logic_vector((addressBits - 1) downto 0);
			  we : in std_logic;
			  data_i : in std_logic_vector((memSize - 1) downto 0);
			  data_o : out std_logic_vector((memSize - 1) downto 0)
		  );
end Memory;

architecture Behavioral of Memory is
	--Declaration of type and signal of a (2**addressBits - 1) element RAM
	--with each element being memSize bit's wide.
	type ram_t is array (0 to (2**addressBits - 1)) of std_logic_vector((memSize - 1) downto 0);
	signal ram : ram_t := (others => (others => '0'));
	signal tempAddress : integer range 0 to (2**addressBits-1);
	
begin
	--process for read and write operation.
	PROCESS(Clk)
	BEGIN
		tempAddress <= CONV_INTEGER(address);
		
		 if(rising_edge(Clk)) then
			  if(we='1') then
					ram(tempAddress) <= data_i;--Writing Data
			  end if;
			  data_o <= ram(tempAddress);--Reading Data
		 end if; 
	END PROCESS;
end Behavioral;
